// Functions associated with the Level class
//-----------------

//-----------------
// Includes libraries and other files
#include "Level.h"
//-----------------

//-----------------
//// CONSTRUCTOR - Level
Level::Level( LPDIRECT3DDEVICE9 device, std::vector<Mesh>* models, Player* player)
	: device_( device), p_models_( models), p_player_( player), fm_( device), module_( ""), level_current_( 0), level_total_( 0)
{}

//// DESTRUCTOR - ~Level
Level::~Level() {
	device_ = nullptr;

	delete_objects();
}
//-----------------

//-----------------
//// FUNCTION - get_module
// return the name of the current module that's being played
std::string Level::get_module() const { return module_; }

//// FUNCTION - get_current_level
// return the number of the current level
int Level::get_current_level() const { return level_current_; }

//// FUNCTION - set_module
// set the name of the module that will be played (changing module also resets the level number)
void Level::set_module( std::string m) {
	// Pre-conditions :- the file name mustn't be empty
	assert( m != "");

	module_ = m;
	fm_.import_essential_module_data( m, level_total_);
	set_current_level( 1);
}

//// FUNCTION - set_current_level
// set the current level
void Level::set_current_level( int l) {
	// Pre-conditions :- the level number must be valid
	assert( l >= 1 && l <= level_total_);

	level_current_ = l;
	extract_current_level();
}

//// FUNCTION - collision
// test for if the player has collided with anything
void Level::collision( const Player* p_player, int& state) {
	// Pre-conditions :- the pointer to the player must be valid
	assert( p_player != nullptr);

	//for( int i( 0); i < objects_.size(); ++i)
	//	objects_[i]->collision( p_player->get_position());

	for( int i( 0); i < end_positions_.size(); ++i) {
		if( end_positions_[i].collision( p_player->get_position())) {
			// ##### NOTE #####
			// When customisation of the end positions has been implemented, there should be a function
			// call to determine what should happen next. For now, just move onto the next level.
			// There will also need to be a 'score' screen that will need to appear before returning to
			// the main menu screen. This will probably require another variable in the Level class and
			// thus will not want the Level class wiped at this point.
			if( level_current_+1 > level_total_) {
				// clear all the level data, change the game state to go back to be menu, and exit this for loop
				reset();
				state = STATE_MENU;
				break;
			}
			else
				// if the next level number is valid, then increment the level
				set_current_level( ++level_current_);
			// ##### NOTE #####
		}

	}
}

//// FUNCTION - render_perspective
// output the currently stored level
void Level::render_perspective() {
	// Pre-conditions :- the device must exist
	assert( device_ != nullptr);

	// update the skybox's position
	skybox_.set_location( p_player_->get_x(), p_player_->get_y(), p_player_->get_z());
	skybox_.render();

	// ##### NOTE #####
	// The commented out code here is for re-applying the Mesh pointers for the objects. If a
	// new item is added to the vector then it all gets reshuffled and the pointers become bad.
	// Uncommenting the code will re-align them to the correct memory locations.
	// It SHOULDN'T be required, but is useful if bugs occur.
	for( int i( 0); i < objects_.size(); i++) {
	//	for( int j( 0); j < p_models_->size(); j++) {
	//		if( objects_[i]->get_file_name() == p_models_->at( j).get_file_name()) {
	//			objects_[i]->set_mesh( &p_models_->at( j));
				objects_[i]->render();
	//		}
	//	}
	}
	// ##### NOTE #####
}

//// FUNCTION - reset
// clear all the data currently held in the Level class
void Level::reset() {
	// Pre-conditions :- none
	assert( true);

	// delete all the models currently saved in this class
	delete_objects();
	// clear the level number and module name
	level_current_ = 0;
	level_total_ = 0;
	module_ = "";
}

//// FUNCTION - extract_current_level
// read the objects for the current level from the module file and place them into the objects list
void Level::extract_current_level() {
	// Pre-conditions :- the module name must exist and the level number must be valid
	assert( module_ != "" && level_current_ > 0);

	delete_objects();
	fm_.import_level_from_module( p_models_, objects_, skybox_, sounds_, p_player_, end_positions_, module_, level_current_);
	//setup_lights();
}

//// FUNCTION - delete_objects
// release all the memory using the heap
void Level::delete_objects() {
	// Pre-conditions :- none
	assert( true);

	for( int i( 0); i < objects_.size(); ++i) {
		delete objects_[i];
		objects_[i] = nullptr;
	}
	objects_.resize( 0);

	for( int i( 0); i < sounds_.size(); ++i) {
		delete sounds_[i];
		sounds_[i] = nullptr;
	}
	sounds_.resize( 0);
}